#include "asgka_implement.h"
#include "global.h"
#include "asgka_space.h"
#include "messageCommon.h"
#include "messageCommonEx.h"
#include "messageMemberList.h"
#include "asgkaCreateAgreementThread.h"
#include "common.h"
#include "messagetype.h"

#include <iostream>
using namespace std;

asgka_implement::asgka_implement()
	:m_tcp_listen(NULL),
	 m_udp_recv(NULL),
	 m_member_center(NULL),
	 m_group_center(NULL)
{}

asgka_implement::~asgka_implement()
{
}

void asgka_implement::asgka_setup(const std::string &mylocalname)
{
	WSAData was;
	WSAStartup(MAKEWORD(2, 2), &was);

	// Initialize the global variables
	localname = mylocalname;
	InitializeCriticalSection(&globalcs);

	char generator[LENGTH];
	strcpy_s(generator, LENGTH,
		"[6322069030959797239974302728815258316709002424839598348999808636855120175466090008089069870442189980465884571393312767672877644162824787053897296527046511, 2160399843694700352574210733609801044755127137866597903735353473997504189822218028062346910851264365516731536283788623762281392086125022828651245680060444]");
	setupSystem(generator, 10);

	m_member_center = new memberCenter();
	m_group_center  = new groupCenter();

	// Create myself
	m_myself = m_member_center->createMember(localname, INADDR_ANY);

	m_tcp_listen = new TCPListenThread(m_member_center, m_group_center);
	m_udp_recv = new UDPRecvThread(m_member_center, m_group_center);
	m_tcp_listen->start();
	m_udp_recv->start();
}

void asgka_implement::asgka_close()
{
	asgka_exit();
	Sleep(ExitWait);
	if (m_group_center != NULL)
		delete m_group_center;
	if (m_member_center != NULL)
		delete m_member_center;
	if (m_tcp_listen != NULL)
		delete m_tcp_listen;
	if (m_udp_recv != NULL)
		delete m_udp_recv;
	closeSystem();
	DeleteCriticalSection(&globalcs);
	WSACleanup();
}

void asgka_implement::createAGroup(const std::string &groupname)
{
	//Create group
	singleGroup *group;
	group = m_group_center->createGroup(groupname, m_myself);

	if (group == NULL)
	{
		cout << "Group named " << groupname << "existed !" << endl;
		return ;
	}

	// Search member
	messageBase *searchmsg = new messageCommon(localname, NET_MESSAGE_SEARCH);
	broadcastMessage(searchmsg);

	// Wait for a moment 
	Sleep(UDPWait);
	std::map<std::string, u_long> member_list;
	chooseAndInvite(member_list, group);

	// Send member list
	publicMemberList(member_list, groupname);

	// Start agreement
	asgkaCreateAgreementThread *pthread = new asgkaCreateAgreementThread(group);
	pthread->start();

	delete searchmsg;
}

void asgka_implement::leaveAGroup(const std::string &groupname)
{
	sendLeaveGroupMsg(groupname);

	// Delete group object
	m_group_center->releaseGroup(groupname);
}

void asgka_implement::joinAGroup(const std::string &groupname, const std::string &groupleadername)
{
	singleMember *pMember = m_member_center->getMemberByName(groupleadername);
	if (pMember == NULL)
		return ;

	messageBase *msg = new messageCommonEx(localname, groupname,  NET_MESSAGE_JOIN_GROUP);
	sendMessageToMember_tcp(msg, pMember);
	delete msg;
}

void asgka_implement::chooseAndInvite(std::map<std::string, u_long> &member_list, singleGroup *group)
{
	messageBase *gpmsg = new messageCommonEx(localname, group->getGroupName(), NET_MESSAGE_GROUP_INVITATION);

	// Choose all of the members
	const std::map<std::string, singleMember *> *all_member = m_member_center->getAddrofMemberList();
	std::map<std::string, singleMember *>::const_iterator it = all_member->begin();
	for (; it != all_member->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;

		// Send invitation
		sendMessageToMember_tcp(gpmsg, it->second);
		member_list.insert(stouvalType(it->second->getMemberName(), it->second->getNetAddr()));
		group->addAMember(it->second);
	}
	delete gpmsg;
}

void asgka_implement::publicMemberList(std::map<std::string, u_long> &member_list, const std::string &groupname)
{
	messageBase *mlmsg = new messageMemberList(groupname, member_list);
	m_group_center->sendMessageToGroup(mlmsg, groupname);
	delete mlmsg;
}

void asgka_implement::sendLeaveGroupMsg(const std::string &groupname)
{
	messageBase *lgmsg = new messageCommonEx(localname, groupname, NET_MESSAGE_LEAVE_GROUP);
	m_group_center->sendMessageToGroup(lgmsg, groupname);
	delete lgmsg;
}

void asgka_implement::asgka_exit()
{
	messageBase *olmsg = new messageCommon(localname, NET_MESSAGE_OFF_LINE);
	m_member_center->sendMessageToAllMember(olmsg);
	delete olmsg;
}
